// Amethyst Pose Script v2
// By: Amethyst Rosencrans

// Customizable Settings
vector offset = <0,0,-0.4>;     // The offset of the sit animation
rotation rot = <0,0,0,1>;       // The rotation of the sit animation
string sit = "Sit";        // The text on the Sit button pie menu
string text = "";       // The floating text above the ball
integer Lockmeister = -1;       // Lockmeister ID (if there are multiple places to sit) 0 for off -1 for auto
integer Touch = TRUE;           // Whether to change animations on touch
integer Sensations = TRUE;      // Send sensations messages when getting on and off
integer randchan = 0;           // Random channel
string Card = "Settings";       // Settings notecard
integer Debug = FALSE;          // Give some aditional information messages
integer Channel = 9;            // Hide/Show listener
key victim=NULL_KEY;
key locker=NULL_KEY;
// Internal variables
key nullkey = NULL_KEY;
string nullstr = "";
integer current = 0;
string lastanim = nullstr;
key posekey = nullkey;
integer hidden = FALSE;
integer line;
key loadkey;
list Anim = []; // Animation names
list Lock = []; // Lockmeister targets
list Sens = []; // Sensations text
list Type = []; // Sensations type
list Amnt = []; // Sensations amount
list Inte = []; // Sensations interval
string amount;
string type;
string mess;
integer gDemon =1338;
integer gVic =1329;
integer gPlugin =1339;
integer gMenuLink =1337;
integer channel_dialog;
key ToucherID;
integer gPage;
list choices; 
// Return a random number between min and max

list pageMenu(list in ,integer page)
{
	list out;
	integer maxpages =llGetListLength(in)/9;
	page = (page)%(maxpages+1);
	out =["<<","Back",">>"];
	integer _listcount =(page *9)+9;
	integer _i=_listcount-9;
	
	for (_i;_i<_listcount;_i++)
	{
		if(_i<=llGetListLength(in)&&llList2String(in,_i)!="")
		out+=llList2String(in,_i);
	}
	return out;
}

integer randBetween(integer min, integer max)
{
    return (integer)(llFrand((float)(max - min)) + min);
}

// Stop the current animation
StopAnimation(string anim)
{
    if(llGetPermissions() & PERMISSION_TRIGGER_ANIMATION && anim != nullstr)
    {
        llStopAnimation(anim);
    }
    lastanim = nullstr;
}

// Start an animation stopping a previous on if needed
StartAnimation(string anim)
{
    if(posekey == llGetPermissionsKey() && 
        llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)
    {
        if(anim)
        {
            llStartAnimation(anim);
        }
        if(lastanim != nullstr && lastanim != anim)
        {
            llStopAnimation(lastanim);
        }
        llStopAnimation("sit");
        llStopAnimation("1a5fe8ac-a804-8a5d-7cbd-56bd83184568");
        lastanim = anim;
    }
}

// Hide the pose ball
HideBall()
{
    llSetAlpha(0.0, ALL_SIDES);
    llSetText(nullstr, <1,1,1>, 1);
}

// Show the poseball
ShowBall()
{
    llSetAlpha(1.0, ALL_SIDES);
    llSetText(text, <1,1,1>, 1);
}

// Generate an ID if -1
integer MyID(integer lm)
{
    if(lm == -1)
    {
        return current + 1;
    }
    return lm;
}

// Setup all the pose ball settings
SetupBall()
{
    llSitTarget(offset, rot);
    llSetSitText(sit);
    llSetText(text, <1,1,1>, 1);
}

// Initiate a notecard reload
LoadCard()
{
    Anim = Lock = Sens = Type = Amnt = Inte = [];
    line = 0;
    if(llGetInventoryType(Card) == INVENTORY_NOTECARD)
    {
        loadkey = llGetNotecardLine(Card, line);
    }
}

SensationsSetup(string name)
{
    integer index = llListFindList(Anim, [ name ]);
    if(index != -1)
    {
        integer interval = llList2Integer(Inte, index);
        type = llList2String(Type, index);
        amount = llList2String(Amnt, index);
        mess = llList2String(Sens, index);
        if((type == "pain" || type == "arousal") && (integer)amount != 0 && interval > 0)
        {
            llSetTimerEvent(interval);
        }
    }
}

displayMenu()
{
		choices = [ "Hide" ];
        integer x;
        string anim = llGetInventoryName(INVENTORY_ANIMATION, current);
        string text = "Choose animation:";
        list tempMain;
        // If we have an animation selected put it on the dialog
        if(anim != nullstr)
        {
            text += "\n\nCurrent animation:\n" + anim;
        }
        
        // Show either a hide or show button
        if(hidden == TRUE)
        {
            choices = [ "Show" ];
        }
        
        // Get a list of up to 11 animations
        while(x<llGetInventoryNumber(INVENTORY_ANIMATION))
        {
            choices += [ llGetSubString(llGetInventoryName(INVENTORY_ANIMATION, x), 0, 23) ];
            x++;
        }
        if(llGetListLength(choices)<11)
		{
			tempMain= [" ","Back"]+choices;
		}
		else
		{
			tempMain+=choices;
			tempMain= pageMenu(tempMain,gPage);
		}
        // Display the dialog
        llDialog(ToucherID, text, tempMain, randchan);
}
    
default
{
    state_entry()
    {
        SetupBall();
        randchan = -randBetween(1, 100000);
        llListen(randchan, nullstr, nullkey, nullstr);
        if(Channel != 0)
        {
            llListen(Channel, nullstr, nullkey, "hide");
            llListen(Channel, nullstr, nullkey, "show");
        }
        LoadCard();
    }

    // To be safe reset script on rez    
    on_rez(integer param)
    {
        //llResetScript();
    }
    
    listen(integer chan, string name, key id, string msg)
    {
        // Handle hide button
        if(llToLower(msg) == "hide")
        {
            hidden = TRUE;
            HideBall();
        }
        // Handle show button
        else if(llToLower(msg) == "show")
        {
            hidden = FALSE;
            if(llAvatarOnSitTarget() == nullkey)
            {
                ShowBall();
            }
        }
		else if(msg=="<<")
	  	{
	  		gPage--;
			integer maxpages =llGetListLength(choices)/9;
			if(gPage<0)
			{
				gPage = maxpages;
			}
			displayMenu();
	  	}
	  	else if(msg==">>")
	  	{
	  		gPage++;
	  		displayMenu();
	  	}
	  	else if(msg=="Back")
	  	{
	  		llMessageLinked(LINK_THIS, gMenuLink, "DV_BASIC", ToucherID);
	  	}         
        else
        {
            // Handle animation selection
            integer x;

            // See if we have a matching animation in inventory        
            while(x<llGetInventoryNumber(INVENTORY_ANIMATION))
            {
                string name = llGetInventoryName(INVENTORY_ANIMATION, x);
            
                if(msg == llGetSubString(name, 0, 23))
                {
                    llSetTimerEvent(0);
                    
                    // If so select it as the current animation
                    // and switch poses
                    current = x;
                    llMessageLinked(LINK_SET, 50, (string)MyID(Lockmeister), posekey);
                    StartAnimation(name);
                    lastanim=name;
                    displayMenu();
                    if(Sensations)
                    {
                        SensationsSetup(name);
                    }
                    return;
                }
                x++;
            }
            
        }
    }
    
    // something changed
    changed(integer change) 
    { 
        if(change & CHANGED_LINK) 
        {
             // Someone sat on us
            posekey = llAvatarOnSitTarget();

            if(posekey != nullkey)
            {
                HideBall();
                llRequestPermissions(posekey,PERMISSION_TRIGGER_ANIMATION);
            }
            else
            {
                llSetTimerEvent(0);
                llMessageLinked(LINK_SET, 51, (string)MyID(Lockmeister), nullkey);
                if(Sensations == TRUE)
                {
                    llMessageLinked(LINK_SET, -8901, "say %o pouts sadly as they dismount the " + llGetObjectName() + ".", "");
                }
                if(hidden == FALSE)
                {
                    ShowBall();
                    
                }
                StopAnimation(lastanim);
                llResetScript();
            }
        }
        if(change & CHANGED_INVENTORY)
        {
            LoadCard();
        }
    }    

    timer()
    {
        if(mess != nullstr)
        {
            llMessageLinked(LINK_SET, -8901, "say " + mess, "");
        }
        llMessageLinked(LINK_SET, -8901, "change " + type + " " + amount, "");
    }
        
    touch_start(integer total_number)
    {
        
    }

    // Handle loading of the config file...
    // Using Xcite format for compatibility
    dataserver(key query_id, string data) 
    {
        if(data != EOF) 
        {
            if(data != nullstr && llGetSubString(data, 0, 0) != "#" && query_id == loadkey)
            {
                list templist = llParseStringKeepNulls(data, ["|"], []);
                string anim = llList2String(templist, 0);
                string lock = llList2String(templist, 1);
                string sens = llList2String(templist, 2);                
                
                // Override sit setting
                if(anim == "sit")
                {
                    if(lock != nullstr)
                    {
                        sit = lock;
                    }   
                }
                // Override text setting
                if(anim == "text")
                {
                    if(lock != nullstr)
                    {
                        text = lock;
                    }   
                }
                // Override offset setting
                if(anim == "offset")
                {
                    if(lock != nullstr)
                    {
                        offset = (vector)lock;
                    }   
                }
                // Override offset setting
                if(anim == "rotation")
                {
                    if(lock != nullstr)
                    {
                        rot = (rotation)lock;
                    }   
                }
                // Add a animation settings entry
                else if(llGetInventoryType(anim) == INVENTORY_ANIMATION && (lock != nullstr || sens != nullstr))
                {
                    Anim += anim;
                    Lock += lock;
                    Sens += sens;
                    Type += llList2String(templist, 3);
                    Amnt += llList2String(templist, 4);
                    Inte += llList2String(templist, 5);
                }
            }
            if(query_id == loadkey)
            {
                line++;                                             // increase line count
                loadkey = llGetNotecardLine(Card, line);            // request next line
            }
        }
        else
        {
            integer x;

            // Update the lockmeister info        
            while(x<llGetInventoryNumber(INVENTORY_ANIMATION))
            {
                integer index = llListFindList(Anim, [ llGetInventoryName(INVENTORY_ANIMATION, x) ]);
                    
                // If we have a current animation update the 
                // lockmeister settings
                if(index != -1)
                {
                    string lock = llList2String(Lock, index);
                    
                    if(lock != nullstr)
                    {
                        llMessageLinked(LINK_SET, 52, (string)(x + 1), lock);
                    }
                }
                x++;
            }
            // Update the poseball
            SetupBall();
            if(Debug)
            {
                llOwnerSay("/me loaded " + (string)llGetListLength(Anim) + " pose settings. Free memory: " + (string)llGetFreeMemory());
            }
        }
    }
    
    //run_time_permissions - launched when llRequestPermissions is used and
    //the script receives the result of that request
    run_time_permissions(integer value) 
    {
        //Check to see if we got permission to animate the avatar
        if (value & PERMISSION_TRIGGER_ANIMATION) 
        {
            string name = llGetInventoryName(INVENTORY_ANIMATION, current);
            llMessageLinked(LINK_SET, 50, (string)MyID(Lockmeister), posekey);
            StartAnimation(name);   
            if(Sensations == TRUE)
            {
                llMessageLinked(LINK_SET, -8901, "say %o gasps with pleasure as they mount the " + llGetObjectName() + ".", "");
            }
            SensationsSetup(name);
        }
    }
    
    link_message(integer sender, integer num, string str, key id)
  	{
  		if(num ==gMenuLink)
  		{
  			if(str==llGetScriptName())
  			{
  				llMessageLinked(LINK_THIS, gDemon, llGetScriptName(), NULL_KEY);
  				ToucherID=id;
		        displayMenu();
		        
  			}
  		}
  	}
}
